package com.ssy.lingxi.member.merchant.serviceimpl.paas;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.RoleAuthVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.RoleConfigVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.RoleVO;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.AuthBO;
import com.ssy.lingxi.member.merchant.model.bo.ButtonBO;
import com.ssy.lingxi.member.merchant.repository.*;
import com.ssy.lingxi.member.merchant.service.paas.IBasePaasService;
import com.ssy.lingxi.member.merchant.service.paas.IPaasRoleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 业务平台 - 角色管理接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-06-13
 */
@Service
public class PaasRoleServiceImpl implements IPaasRoleService {
    @Resource
    private RoleRepository roleRepository;

    @Resource
    private MemberConfigRepository memberConfigRepository;

    @Resource
    private RoleTypeRepository roleTypeRepository;

    @Resource
    private MemberBusinessTypeRepository businessTypeRepository;

    @Resource
    private MemberTypeRepository memberTypeRepository;

    @Resource
    private MenuRepository menuRepository;

    @Resource
    private IBasePaasService basePaasService;

    @Override
    public Wrapper<Long> addRole(RoleVO roleVO) {
        if(roleRepository.existsByRoleName(roleVO.getRoleName())) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_EXISTS);
        }

        RoleTypeDO roleTypeDO = roleTypeRepository.findFirstByTypeEnum(roleVO.getRoleTypeEnum());
        if(roleTypeDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_TYPE_DOES_NOT_EXIST);
        }

        MemberTypeDO memberTypeDO = memberTypeRepository.findByTypeEnum(roleVO.getMemberTypeEnum());
        if(memberTypeDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_TYPE_DOES_NOT_EXIST);
        }

        //如果业务类型不存在则新增
        MemberBusinessTypeDO businessTypeDO = businessTypeRepository.findFirstByBusinessTypeName(roleVO.getBusinessTypeName());
        if(businessTypeDO == null) {
            businessTypeDO = new MemberBusinessTypeDO();
            businessTypeDO.setRelType(MemberRelationTypeEnum.OTHER.getCode());
            businessTypeDO.setBusinessTypeName(roleVO.getBusinessTypeName());
            businessTypeDO = businessTypeRepository.saveAndFlush(businessTypeDO);
        }

        //根据业务类型和会员类型查找，如果已经存在角色则不允许创建
        if(roleRepository.existsByBusinessTypeAndMemberTypeAndStatus(businessTypeDO, memberTypeDO, EnableDisableStatus.ENABLE.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_EXISTS);
        }

        RoleDO roleDO = new RoleDO();
        roleDO.setRoleName(roleVO.getRoleName());
        //默认启用状态
        roleDO.setStatus(EnableDisableStatus.ENABLE.getCode());
        roleDO.setRoleType(roleTypeDO);
        roleDO.setMemberType(memberTypeDO);
        roleDO.setBusinessType(businessTypeDO);
        roleDO.setRelType(MemberRelationTypeEnum.OTHER.getCode());
        //设置权限为空，避免Null值
        RoleAuthDO roleAuthDO = new RoleAuthDO();
        roleAuthDO.setAuth(new ArrayList<>());
        roleDO.setRoleAuth(roleAuthDO);
        roleRepository.saveAndFlush(roleDO);

        return Wrapper.success(roleDO.getId());
    }

    /**
     * 更新角色
     * @param roleVO 接口参数
     * @return 更新结果
     */
    @Override
    public Wrapper<Void> updateRole(RoleVO roleVO) {

        RoleDO roleDO = roleRepository.findById(roleVO.getId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        //如果已经存在同名的角色，返回角色已经存在的错误
        if(roleRepository.existsByRoleNameAndIdNot(roleVO.getRoleName(), roleVO.getId())) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_EXISTS);
        }

        RoleTypeDO roleTypeDO = roleTypeRepository.findFirstByTypeEnum(roleVO.getRoleTypeEnum());
        if(roleTypeDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_TYPE_DOES_NOT_EXIST);
        }

        MemberTypeDO memberTypeDO = memberTypeRepository.findByTypeEnum(roleVO.getMemberTypeEnum());
        if(memberTypeDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_TYPE_DOES_NOT_EXIST);
        }

        //如果业务类型不存在则新增
        MemberBusinessTypeDO businessTypeDO = businessTypeRepository.findFirstByBusinessTypeName(roleVO.getBusinessTypeName());
        if(businessTypeDO == null) {
            businessTypeDO = new MemberBusinessTypeDO();
            businessTypeDO.setRelType(MemberRelationTypeEnum.OTHER.getCode());
            businessTypeDO.setBusinessTypeName(roleVO.getBusinessTypeName());
            businessTypeDO = businessTypeRepository.saveAndFlush(businessTypeDO);
        }

        //不修改原来的状态
        roleDO.setRoleName(roleVO.getRoleName());
        roleDO.setRoleType(roleTypeDO);
        roleDO.setMemberType(memberTypeDO);
        roleDO.setBusinessType(businessTypeDO);

        roleRepository.saveAndFlush(roleDO);

        return Wrapper.success();
    }

    /**
     * 删除角色
     * @param roleVO 接口参数
     * @return 删除结果
     */
    @Override
    public Wrapper<Void> deleteRole(RoleVO roleVO) {
        RoleDO roleDO = roleRepository.findById(roleVO.getId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        if(!CollectionUtils.isEmpty(roleDO.getMembers())) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_CAN_NOT_UPDATE_OR_DELETE);
        }

        roleRepository.delete(roleDO);
        return Wrapper.success();
    }

    /**
     * 更改角色状态
     *
     * @param roleVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateRoleStatus(RoleVO roleVO) {
        RoleDO roleDO = roleRepository.findById(roleVO.getId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        if(!CollectionUtils.isEmpty(roleDO.getMembers())) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_CAN_NOT_UPDATE_OR_DELETE);
        }

        roleDO.setStatus(roleVO.getStatus());

        roleRepository.saveAndFlush(roleDO);

        return Wrapper.success();
    }

    /**
     * 设置角色权限（关联的菜单和按钮）
     * @param roleAuthVO 接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> setRoleAuth(RoleAuthVO roleAuthVO) {
        RoleDO roleDO = roleRepository.findById(roleAuthVO.getId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        List<AuthBO> authBOList = new ArrayList<>();
        List<MenuDO> menuDOList = menuRepository.findAll();

        Set<Long> menuPassIdSet = roleAuthVO.getAuth().keySet();

        for (Long menuPaasId : menuPassIdSet) {
            MenuDO menuDO = menuDOList.stream().filter(c -> c.getPaasId().equals(menuPaasId)).findFirst().orElse(null);
            if (menuDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST, "PassId:" + menuPaasId + "的菜单不存在");
            }

            Long parentMenuId = 0L;
            if (!menuDO.getParentId().equals(0L)) {
                MenuDO upperMenuDO = menuDOList.stream().filter(c -> c.getId().equals(menuDO.getParentId())).findFirst().orElse(null);
                if (upperMenuDO == null) {
                    return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST, "PassId:" + menuPaasId + "的父菜单不存在");
                }

                parentMenuId = upperMenuDO.getId();
            }

            AuthBO userAuthBO;

            //判断按钮是否存在
            List<Long> buttonPaasIdList = roleAuthVO.getAuth().get(menuPaasId);
            if (!CollectionUtils.isEmpty(buttonPaasIdList)) {
                List<Long> existButtonPaasIdList = menuDO.getButtons().stream().map(MenuButtonDO::getPaasId).collect(Collectors.toList());
                if (!existButtonPaasIdList.containsAll(buttonPaasIdList)) {
                    return Wrapper.fail(ResponseCode.MC_MS_BUTTON_DOES_NOT_EXIST);
                }

                List<ButtonBO> authButtonList = menuDO.getButtons().stream().filter(c -> buttonPaasIdList.contains(c.getPaasId())).map(c -> new ButtonBO(c.getId(), c.getName(), c.getUrl(), c.getCode(), c.getAttrs())).collect(Collectors.toList());
                userAuthBO = new AuthBO(menuDO.getId(), parentMenuId, menuDO.getCode(), menuDO.getUrl(), menuDO.getTitle(), menuDO.getOrder(), menuDO.getSource(), menuDO.getAttrs(), authButtonList, EnableDisableStatus.ENABLE.getCode());
            } else {
                userAuthBO = new AuthBO(menuDO.getId(), parentMenuId, menuDO.getCode(), menuDO.getUrl(), menuDO.getTitle(), menuDO.getOrder(), menuDO.getSource(), menuDO.getAttrs(),  new ArrayList<>(), EnableDisableStatus.ENABLE.getCode());
            }

            authBOList.add(userAuthBO);
        }

        roleDO.getRoleAuth().setAuth(authBOList);
        roleRepository.saveAndFlush(roleDO);

        //重新构建权限
        return basePaasService.rebuildAuth(roleDO);
    }

    /**
     * 设置角色关联的配置资料
     *
     * @param configVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> setRoleConfig(RoleConfigVO configVO) {
        RoleDO roleDO = roleRepository.findById(configVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        if(CollectionUtils.isEmpty(configVO.getConfigIds())) {
            roleDO.getConfigs().clear();
        } else {
            List<MemberConfigDO> configDOList = memberConfigRepository.findAllById(configVO.getConfigIds());
            if(configDOList.size() != configVO.getConfigIds().size()) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_CONFIG_DOES_NOT_EXIST);
            }

            roleDO.setConfigs(new HashSet<>(configDOList));
        }

        roleRepository.saveAndFlush(roleDO);

        return Wrapper.success();
    }
}
